package controller;

import java.io.IOException;
import java.sql.SQLException;
import java.util.GregorianCalendar;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import model.Benutzer;
import model.Ebene;
import model.Feld;
import model.Gruppe;

/**
 * Servlet implementation class Einrichten
 */
/**
 * @author Daniel Eischer, Jonas Gutermuth
 *
 */
@WebServlet({"/Einrichten", "/einrichten", "/Einrichten.html", "/einrichten.html"})
public class Einrichten extends SessionControll {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public Einrichten() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    private int idEbene = -1; 

	/**
	 * Übergabe der Felder, Verantwortlichen und Redakteure der gewählten Ebene an die JSP. Abfangen von ungültigen Aufrufen und unberechtigtem Zugriff 
	 * 
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 * 
	 */    
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		if (super.gruppePruefen(request, response, Gruppe.ADMIN)) {
			try {
				if(request.getParameter("ebenenId") != null){
					idEbene = Integer.parseInt(request.getParameter("ebenenId"));
					request.setAttribute("vorhandeneFelder", ebenenRepository.getNeusteEbeneNachId(idEbene).getFeld());
					request.setAttribute("vorhandeneEbene", ebenenRepository.getNeusteEbeneNachId(idEbene));
					request.setAttribute("redakteure", gruppenRepository.getGruppeNachId(Gruppe.REDAKTEUR).getBenutzer());
					request.setAttribute("verantwortliche", gruppenRepository.getGruppeNachId(Gruppe.ORDNUNGSEBENENVERANTWORTLICHER).getBenutzer());
					request.setAttribute("tabsController", "Einrichten"); // um die Tabs richtig anzuzeigen
					RequestDispatcher view;
					view = request.getRequestDispatcher("Einrichten.jsp");
					view.forward(request, response);					
				}else{
					response.sendRedirect("Fehler?fehler=Sie haben versucht eine unmögliche Handlung auszuführen.&weiterleitung=AufgabenListe");
				}	
			} catch (ClassNotFoundException e) {
				new helper.Logging("Fehler Fxxx",e.toString(), benutzerRepository.getBenutzerNachEmail((String) request.getSession().getAttribute("email")), (byte)1);
				e.printStackTrace();
			} catch (SQLException e) {
				new helper.Logging("Fehler Fxxx",e.toString(), benutzerRepository.getBenutzerNachEmail((String) request.getSession().getAttribute("email")), (byte)1);
				e.printStackTrace();
			} catch (NumberFormatException e){
				new helper.Logging("Fehler Fxxx",e.toString(), benutzerRepository.getBenutzerNachEmail((String) request.getSession().getAttribute("email")), (byte)1);
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 * 
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		if(super.loginPruefen(request,response)) {
			
			//Daten der Ebene und ihrer Felder anfordern
			String titel = request.getParameter("titel");
			String[] verantwortliche = request.getParameterValues("verantwortliche");
			String[] redakteur = request.getParameterValues("redakteur");
			String prosa = request.getParameter("prosa");
			idEbene = Integer.parseInt(request.getParameter("ebenenId"));
			String[] name = request.getParameterValues("name");
			String[] dezernat2 = request.getParameterValues("dezernat2");
			
			//Zeitpunkt festlegen für Speichern, alle Felder müssen den gleichen Zeitstempel besitzen
			long time = (new GregorianCalendar()).getTimeInMillis();
			int[] id = null;
			int[] typ = null;		
			if(request.getParameterValues("id") != null && request.getParameterValues("typ") != null){
				// id und typ der Felder einlesen
				id = new int[request.getParameterValues("id").length];
				for (int i = 0; i < request.getParameterValues("id").length; i++) {
					id[i] = Integer.parseInt(request.getParameterValues("id")[i]);
				}
				
				typ = new int[request.getParameterValues("typ").length];
				for (int i = 0; i < request.getParameterValues("typ").length; i++) {
					typ[i] = Integer.parseInt(request.getParameterValues("typ")[i]);
				}
			}
			
			
			try {
				
				if(request.getParameter("ebenenId") != null){
					//# # # # # # # #
					//#	Speichern   #
					//# # # # # # # # 
					if("Speichern".equals(request.getParameter("speichern"))) {
						System.out.println("##### Ebenenvergleich gestartet #####");
						Ebene altEbene = ebenenRepository.getNeusteEbeneNachId(idEbene);
						
						// ### Prüfen ob Änderung
						boolean changed = false;
						
						// Prosaänderung
						if (!"on".equals(prosa) && ebenenRepository.getNeusteEbeneNachId(idEbene).getProsaId() != 0) {
							changed = true;
							System.out.println("Changed"+1);
						} else if (ebenenRepository.getNeusteEbeneNachId(idEbene).getProsaId() == 0 && "on".equals(prosa)) {
							changed = true;
							System.out.println("Changed"+2);
						}
						
						// Titeländerung
						if(altEbene.getName() != null) {
							if(!altEbene.getName().equals(titel)) {
								changed = true;
								System.out.println("Changed"+3);
							}
						}
						//Felderänderung
						if(!changed) {
							Feld[] alteFelder = altEbene.getFeld();
							if (id != null && alteFelder != null && alteFelder.length == id.length) {
								for (int i = 0; i < id.length; i++) {
									if(alteFelder[i].getId() != id[i] 
									|| !alteFelder[i].getName().equals(name[i])
									|| alteFelder[i].getTyp() != typ[i] 
									|| alteFelder[i].isDez2relevant() != ("1".equals(dezernat2[i]))){ 	
										changed = true; 	
										break; 	
									}
								}
							} else {
								changed = true; 	
								System.out.println("Changed"+5);
							}
						}
						
						String verantwortlicheReturn = stringArrayToString(verantwortliche);
						String redakteurReturn = stringArrayToString(redakteur);
						
						//Prüfen ob etwas an der Ebene geändert wurde
						if(changed) {
							boolean neuesFeldErstellt = false;
							//Prosa Aktualisieren oder falls nicht vorhanden neues Prosafeld erstellen
							int prosaId = 0;
							if("on".equals(prosa)) {
								// altes Prosa vorhanden und Prosa aktiviert für aktuelle Ebene
								if(altEbene.getProsa() != null) {
									System.out.println("### Altes Prosafeld wird beibehalten");
									prosaId = altEbene.getProsa().getId();
									Feld feld = new Feld(prosaId, 1, "prosa", false, time, felderRepository.getNeustesFeldNachId(prosaId).getWert());
									felderRepository.saveFeld(feld);
									// alte Ebene besaß kein Prosa und Prosa aktiviert für aktuelle Ebene
								} else if(altEbene.getProsa() == null) {
									System.out.println("### Neues Prosafeld wird erstellt");
									prosaId = (felderRepository.newFeld(1, "prosa", false, "Hier Prosatext einfügen", time)).getId();
									neuesFeldErstellt = true;
								}
							} else {
								System.out.println("### keine Prosa");
								prosaId = 0;
							}	
							// neue Felder erstellen oder Bestehende aktualisieren
							if(id != null){		
								for (int i = 0; i < typ.length; i++) {
									// Neues Feld anlegen da noch nicht vorhanden.
									if(id[i] == -1){
										System.out.println("### Neues Feld "+name[i]+" gefunden. Feld wird angelegt.");
										id[i] = (felderRepository.newFeld(typ[i], name[i], ("1".equals(dezernat2[i])) , "", time)).getId();
										neuesFeldErstellt = true;
										// Bestehendes Feld aktualisieren
									} else {
										System.out.println("### Altes Feld "+name[i]+" gefunden. Feld wird geändert.");
										Feld feld = new Feld(id[i], typ[i], name[i], ("1".equals(dezernat2[i])), time, felderRepository.getNeustesFeldNachId(id[i]).getWert());
										felderRepository.saveFeld(feld);
									}
								}
							}
							// Werte aus Arrays für Ebenen speichern vorbereiten
							String feldReturn = intArrayToString(id);
							String unteridReturn = ebeneArrayToString(ebenenRepository.getNeusteEbeneNachId(idEbene).getUnterelement());
							
							// Wenn keine Felder vorhanden sind und keine Prosa wird die Ebene sofort mit akzeptiert gespeichert, da keine Bearbeitung notwendig ist
							if("".equals(feldReturn) && !"on".equals(prosa)) {
								Ebene ebeneTemp = new Ebene(idEbene, titel, prosaId, time, Ebene.ZUSTAND_AKZEPTIERT_BEIDE, verantwortlicheReturn, redakteurReturn, unteridReturn, feldReturn);
								ebenenRepository.saveEbene(ebeneTemp);
								// Alle Änderungen an der Ebene speichern
							} else {
								Ebene ebeneTemp = new Ebene(idEbene, titel, prosaId, time, neuesFeldErstellt?Ebene.ZUSTAND_UNBEARBEITET:ebenenRepository.getNeusteEbeneNachId(idEbene).getRedaktionszustand(), verantwortlicheReturn, redakteurReturn, unteridReturn, feldReturn);
								ebenenRepository.saveEbene(ebeneTemp);
							}
						} else {
							System.out.println("### Ebene muss nicht geändert werden");
						}
						
						// Redakteure bei alten Ebenenen anpassen
						Ebene[] alteEbene = ebenenRepository.getEbeneNachId(idEbene);						
						
						if("".equals(redakteurReturn) || redakteur == null) {
							for (int j = 0; j < alteEbene.length; j++) {
								alteEbene[j].setRedakteur(new Benutzer[0]);
							}
						} else {
							Benutzer[] redakteurTemp = new Benutzer[redakteur.length];
							for (int i = 0; i < redakteur.length; i++) {
								redakteurTemp[i] = benutzerRepository.getBenutzerNachId(Integer.parseInt(redakteur[i]));
							}
							for (int j = 0; j < alteEbene.length; j++) {
								alteEbene[j].setRedakteur(redakteurTemp);
							}

						}
						
						// Verantwortliche bei alten Ebenenen anpassen
						if("".equals(verantwortlicheReturn) || verantwortliche == null) {
							for (int j = 0; j < alteEbene.length; j++) {
								alteEbene[j].setVerantwortlich(new Benutzer[0]);
							}
						} else {
							Benutzer[] verTemp = new Benutzer[verantwortliche.length];
							for (int i = 0; i < verantwortliche.length; i++) {
								verTemp[i] = benutzerRepository.getBenutzerNachId(Integer.parseInt(verantwortliche[i]));
							}
							for (int j = 0; j < alteEbene.length; j++) {
								alteEbene[j].setVerantwortlich(verTemp);
							}

						}
						
						response.sendRedirect("Einrichten?ebenenId="+idEbene);	
					} 
					
				}else {
					response.sendRedirect("Fehler?fehler=Sie haben versucht eine unmögliche Handlung auszuführen.&weiterleitung=AufgabenListe");
				}
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * @param array übergebenes String Array
	 * @return übergebenes Array als ein String getrennt per ;
	 */
	private String stringArrayToString(String[] array) {
		String returnString = "";
		if (array != null) {
			for (int i = 0; i < array.length; i++) {
				returnString += array[i] + ";";
			}
			if(returnString.endsWith(";")) {
				returnString = returnString.substring(0, (returnString.length()-1));
			}
		}
		return returnString;
	}
	/**
	 * @param array übergebenes int Array
	 * @return übergebenes Array als ein String getrennt per ;
	 */
	private String intArrayToString(int[] array) {
		String returnString = "";
		if (array != null) {
			for (int i = 0; i < array.length; i++) {
				returnString += array[i] + ";";
			}
			if(returnString.endsWith(";")) {
				returnString = returnString.substring(0, (returnString.length()-1));
			}
		}
		return returnString;
	}
	
	/**
	 * @param array übergebenes Ebenen Array
	 * @return übergebene Ids des Ebenen Arrays als ein String getrennt per ;
	 */
	private String ebeneArrayToString(Ebene[] array) {
		String returnString = "";
		if (array != null) {
			for (int i = 0; i < array.length; i++) {
				returnString += array[i].getId() + ";";
			}
			if(returnString.endsWith(";")) {
				returnString = returnString.substring(0, (returnString.length()-1));
			}
		}
		return returnString;
	}	


}
